package com.ww.scm.service;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.Criterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.ww.core.exception.ServiceException;
import com.ww.core.orm.Page;
import com.ww.core.orm.PropertyFilter;
import com.ww.core.utils.DateUtils;
import com.ww.scm.constants.Constants;
import com.ww.scm.entity.mat.Bill;
import com.ww.scm.entity.mat.Storage;
import com.ww.scm.entity.mat.Transaction;
import com.ww.scm.entity.mat.TransactionDetail;
import com.ww.scm.entity.pub.Dictionary;
import com.ww.scm.repository.mat.AccountRepository;
import com.ww.scm.repository.mat.BillRepository;
import com.ww.scm.repository.mat.StorageRepository;
import com.ww.scm.repository.mat.TransactionDetailRepository;
import com.ww.scm.repository.mat.TransactionRepository;
import com.ww.scm.repository.pub.DictionaryRepository;
import com.ww.scm.repository.pub.SequenceRepository;
import com.ww.scm.valueObject.mat.BillDetailVo;
import com.ww.scm.valueObject.mat.BillVo;

//Spring Bean的标识.
@Component
// 默认将类中的所有函数纳入事务管理.
@Transactional
public class StorageManager {
	/*
	 * 日志类
	 */
	private static Logger logger = LoggerFactory.getLogger(StorageManager.class);

	/*
	 * 定义Repository
	 */
	private BillRepository billRepository;
	private TransactionRepository transactionRepository;
	private TransactionDetailRepository transactionDetailRepository;
	private StorageRepository storageRepository;
	private AccountRepository accountRepository;
	private DictionaryRepository dictionaryRepository;
	private SequenceRepository sequenceRepository;

	/*
	 * 注入Repository
	 */
	@Autowired
	public void setBillRepository(BillRepository billRepository) {
		this.billRepository = billRepository;
	}
	@Autowired
	public void setTransactionRepository(TransactionRepository transactionRepository) {
		this.transactionRepository = transactionRepository;
	}
	@Autowired
	public void setTransactionDetailRepository(
			TransactionDetailRepository transactionDetailRepository) {
		this.transactionDetailRepository = transactionDetailRepository;
	}
	@Autowired
	public void setStorageRepository(StorageRepository storageRepository) {
		this.storageRepository = storageRepository;
	}
	@Autowired
	public void setAccountRepository(AccountRepository accountRepository) {
		this.accountRepository = accountRepository;
	}
	@Autowired
	public void setDictionaryRepository(DictionaryRepository dictionaryRepository) {
		this.dictionaryRepository = dictionaryRepository;
	}
	@Autowired
	public void setSequenceRepository(SequenceRepository sequenceRepository) {
		this.sequenceRepository = sequenceRepository;
	}
	
	/*
	 * 业务方法
	 */
	
	/**
	 * 按属性过滤条件列表分页查找单据对象.
	 * @param page 分页参数.
	 * @param filters 查询参数
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
	 */
	@Transactional(readOnly = true)
	public Page<Bill> findBill(Page<Bill> page, List<PropertyFilter> filters) {
		return billRepository.findPage(page, filters);
	}
	
	/**
	 * 查询单据对象按HQL分页查询.
	 * 
	 * @param page 分页参数.
	 * @param hql hql语句.
	 * @param values 命名参数,按名称绑定.
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
	 */
	@Transactional(readOnly = true)
	public Page<Bill> findBill(Page<Bill> page, String hql,Map<String, ?> values) {
		return billRepository.findPage(page, hql, values);
	}

	/**
	 * 查询单据对象按HQL分页查询.
	 * 
	 * @param page 分页参数.
	 * @param hql hql语句.
	 * @param values 数量可变的查询参数,按顺序绑定.
	 * 
	 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
	 */
	@Transactional(readOnly = true)
	public Page<Bill> findBill(Page<Bill> page, String hql, Object... values) {
		return billRepository.findPage(page, hql, values);
	}
	
	public Page<Bill> findPage(Page<Bill> page, Criterion... criterions){
		return billRepository.findPage(page, criterions);
	}

	/**
	 * 查询单据对象通过单据主键.
	 * 
	 * @param billId 单据主键.
	 * 
	 * @return 单据对象.
	 */
	@Transactional(readOnly = true)
	public Bill findBillById(String billId) {
		return billRepository.get(billId);
	}
	
	/**
	 * 查询单据对象通过单据编号.
	 * 
	 * @param billCode 单据编号.
	 * 
	 * @return 单据对象.
	 */
	@Transactional(readOnly = true)
	public Bill findBillByCode(String billCode) {
		return billRepository.findUniqueBy("billCode", billCode);
	}
	
	public String randomBillCode(String billType) {
		Dictionary dictionary=dictionaryRepository.get(billType);
		String currentDate=DateUtils.getCurrentDate();
		StringBuffer codeBuffer=new StringBuffer();
		codeBuffer.append(dictionary.getCode());
		codeBuffer.append(Constants.LINE);
		codeBuffer.append(currentDate);
		codeBuffer.append(Constants.LINE);
		int sequence=billRepository.getNextSequence(billType,currentDate);
		codeBuffer.append(sequence);
		return codeBuffer.toString();
	}	
	
	@Transactional(readOnly = true)
	public List<Bill> findBill() {
		return billRepository.getAll();
	}

	/**
	 * 按属性过滤条件列表查找单据对象列表.
	 * 
	 * @param filters 查询参数.
	 * 
	 * @return 单据对象列表.
	 */
	@Transactional(readOnly = true)
	public List<Bill> findBillBy(List<PropertyFilter> filters) {
		return billRepository.find(filters);
	}

	/**
	 * 按属性查找单据对象列表, 匹配方式为相等.
	 * 
	 * @param filters 查询参数.
	 * 
	 * @return 单据对象列表.
	 */	
	@Transactional(readOnly = true)
	public List<Bill> findBillBy(String propertyName, String value) {
		return billRepository.findBy(propertyName, value);
	}
	
	/**
	 * 按属性过滤条件列表查找事务明细对象列表.
	 * 
	 * @param filters 查询参数.
	 * 
	 * @return 事务明细对象列表.
	 */
	@Transactional(readOnly = true)
	public List<TransactionDetail> findTransactionDetailBy(List<PropertyFilter> filters) {
		return transactionDetailRepository.find(filters);
	}
	
	/**
	 * 删除单据
	 * @param billId 单据主键
	 * @param operator 操作人主键
	 */
	public void deleteBill(String billId, String operator) {
		Bill bill = billRepository.get(billId);
		deleteBill(bill, operator);
	}
	
	/**
	 * 删除单据
	 * @param bill 单据对象
	 * @param operator 操作人主键
	 */
	public void deleteBill(Bill bill, String operator) {
		Transaction transaction = bill.getLastTransaction();
		billRepository.delete(bill, operator);
		deleteTransaction(transaction, operator);
	}

	/**
	 * 删除事务
	 * @param transactionId 事务主键
	 * @param operator 操作人主键
	 */
	public void deleteTransaction(String transactionId, String operator) {
		transactionRepository.delete(transactionId, operator);
		rollbackAndDeleteTransaction(transactionId, operator);
	}

	/**
	 * 删除事务
	 * @param transaction 事务对象
	 * @param operator 操作人主键
	 */
	public void deleteTransaction(Transaction transaction, String operator) {
		transactionRepository.delete(transaction, operator);
		rollbackAndDeleteTransaction(transaction, operator);
	}

	/**
	 * 回滚事务
	 * @param transactionId 事务主键
	 * @param operator 操作人主键
	 */
	public void rollbackTransaction(String transactionId, String operator) {
		Transaction transaction = transactionRepository.get(transactionId);
		rollbackTransaction(transaction, operator);
	}
	
	/**
	 * 回滚事务
	 * @param transaction 事务对象
	 * @param operator 操作人主键
	 */
	public void rollbackTransaction(Transaction transaction, String operator) {
		transaction.rollback(storageRepository, accountRepository, operator);
	}
	
	/**
	 * 回滚事务同时删除事务明细
	 * @param transactionId 事务主键
	 * @param operator 操作人主键
	 */
	public void rollbackAndDeleteTransaction(String transactionId, String operator) {
		Transaction transaction = transactionRepository.get(transactionId);
		rollbackAndDeleteTransaction(transaction, operator);
	}	
	
	/**
	 * 回滚事务同时删除事务明细
	 * @param transaction 事务对象
	 * @param operator 操作人主键
	 */
	public void rollbackAndDeleteTransaction(Transaction transaction, String operator) {
		for (TransactionDetail transactionDetail : transaction.getTransactionDetail()) {
			deleteTransactionDetail(transactionDetail,operator);
		}
	}

	/**
	 * 删除事务明细
	 * @param transactionDetailId 事务明细主键
	 * @param operator 操作人主键
	 */
	public void deleteTransactionDetail(String transactionDetailId,String operator) {
		TransactionDetail transactionDetail = transactionDetailRepository.get(transactionDetailId);
		deleteTransactionDetail(transactionDetail, operator);
	}

	/**
	 * 删除事务明细
	 * @param transactionDetail 事务明细对象
	 * @param operator 操作人主键
	 */
	public void deleteTransactionDetail(
			TransactionDetail transactionDetail, String operator) {
		transactionDetailRepository.delete(transactionDetail, operator);
		transactionDetail.rollbackAccount(accountRepository, operator);
		transactionDetail.rollbackStorage(storageRepository, operator);
	}
	
	@Transactional(readOnly = true)
	public Storage findBillByMaterielId(String materielId) {
		return storageRepository.findUniqueBy("materiel.id", materielId);
	}
	
	@Transactional(readOnly = true)
	public List<Storage> findStorageBy(String propertyName, String value) {
		return storageRepository.findBy(propertyName, value);
	}
	
	@Transactional(readOnly = true)
	public List<Storage> findStorageBy(List<PropertyFilter> filters) {
		return storageRepository.find(filters);
	}
	
	/**
	 * 保存单据
	 * @param billVo 单据业务对象
	 */
	public Bill saveBill(BillVo billVo) {
		String operator = billVo.getOperator();
		Date now=new Date();
		Bill bill;
		Transaction transaction;
		if (StringUtils.isNotBlank(billVo.getId())) {
			//如果单据不为空就得到单据对象
			bill = billRepository.get(billVo.getId());
			if (bill==null){
				logger.error("单据不能为空，不能找到主键为：'{}'单据.",billVo.getId());
				throw new ServiceException("单据不能为空，不能找到主键："+billVo.getId()+"单据.");
			}
			//如果事务ID不为空,就拿到单据最后一个事务冲回.
			Transaction lastTransaction = bill.getLastTransaction();
			String transactionId=billVo.getTransactionId();
			if (StringUtils.isBlank(transactionId)){
				//新增事务
				//冲回最后一个事务.
				//如果事务ID为空就回滚事务但是不删除事务明细.
				rollbackTransaction(lastTransaction, operator);
				String transactionTypeId=billVo.getTransactionTypeId();
				transaction=StorageFactory.getInstance().createTransaction(transactionTypeId);
				transaction.setSysFlag(Constants.SYS_FLAG_USEING);
				transaction.setCreateTime(DateUtils.formatDateHms(now));
				transaction.setCreator(operator);
				transaction.setLastModifiedTime(DateUtils.formatDateHms(now));
				transaction.setLastModifier(operator);
			}else{
				//修改事务
				//只能冲回最后一个事务，如果不是单据最后一个事务就抛错.
				if (transactionId.equals(lastTransaction.getId())){
					//如果事务ID不为空就回滚事务同时删除事务明细.
					rollbackAndDeleteTransaction(lastTransaction, operator);
					transaction=lastTransaction;
				}else{
					logger.error("只能冲回最后一个事务,事务主键:'{}'.不是单据:'{}'最后一个事务.",transactionId,billVo.getId());
					throw new ServiceException("只能冲回最后一个事务,事务主键:'"+transactionId+"'.不是单据:'"+billVo.getId()+"'最后一个事务.");
				}
			}
		} else {
			//如果单据为空就创建单据和事务
			String billTypeId = billVo.getBillTypeId();
			//如果单据ID为空通过单据类型ID创建单据对象
			bill = StorageFactory.getInstance().createBill(dictionaryRepository,billTypeId);
			bill.setSysFlag(Constants.SYS_FLAG_USEING);
			bill.setBillCode(randomBillCode(billTypeId));
			bill.setBillDate(billVo.getBillDate());
			bill.setFillTime(billVo.getFillTime());			
			bill.setCreator(operator);
			bill.setCreateTime(DateUtils.formatDateHms(now));
			//通过事务类型ID创建一个事务
			String transactionTypeId=billVo.getTransactionTypeId();
			transaction=StorageFactory.getInstance().createTransaction(transactionTypeId);
			transaction.setSysFlag(Constants.SYS_FLAG_USEING);
			transaction.setCreateTime(DateUtils.formatDateHms(now));
			transaction.setLastModifiedTime(DateUtils.formatDateHms(now));
			transaction.setCreator(operator);
			transaction.setLastModifier(operator);
		}
		//transactionRepository.save(transaction);
		if(StringUtils.isNotBlank(billVo.getOtherDic1Id())){
			Dictionary otherdic1 = dictionaryRepository.get(billVo.getOtherDic1Id());
			bill.setOtherDic1(otherdic1);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic2Id())){
			Dictionary otherdic2 = dictionaryRepository.get(billVo.getOtherDic2Id());
			bill.setOtherDic2(otherdic2);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic3Id())){
			Dictionary otherdic3 = dictionaryRepository.get(billVo.getOtherDic3Id());
			bill.setOtherDic3(otherdic3);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic4Id())){
			Dictionary otherdic4 = dictionaryRepository.get(billVo.getOtherDic4Id());
			bill.setOtherDic4(otherdic4);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic5Id())){
			Dictionary otherdic5 = dictionaryRepository.get(billVo.getOtherDic5Id());
			bill.setOtherDic5(otherdic5);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic6Id())){
			Dictionary otherdic6 = dictionaryRepository.get(billVo.getOtherDic6Id());
			bill.setOtherDic6(otherdic6);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic7Id())){
			Dictionary otherdic7 = dictionaryRepository.get(billVo.getOtherDic7Id());
			bill.setOtherDic7(otherdic7);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic8Id())){
			Dictionary otherdic8 = dictionaryRepository.get(billVo.getOtherDic8Id());
			bill.setOtherDic8(otherdic8);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic9Id())){
			Dictionary otherdic9 = dictionaryRepository.get(billVo.getOtherDic9Id());
			bill.setOtherDic9(otherdic9);
		} 
		if(StringUtils.isNotBlank(billVo.getOtherDic10Id())){
			Dictionary otherdic10 = dictionaryRepository.get(billVo.getOtherDic10Id());
			bill.setOtherDic10(otherdic10);
		} 
		if(StringUtils.isNotBlank(billVo.getOriginEntityId())){
			Dictionary originEntity = dictionaryRepository.get(billVo.getOriginEntityId());
			bill.setOriginEntity(originEntity);
		}
		if(StringUtils.isNotBlank(billVo.getTargetEntityId())){
			Dictionary targetEntity = dictionaryRepository.get(billVo.getTargetEntityId());
			bill.setTargetEntity(targetEntity);
		}
		
		bill.setValue1(billVo.getValue1());
		bill.setValue2(billVo.getValue2());
		bill.setValue3(billVo.getValue3());
		bill.setValue4(billVo.getValue4());
		bill.setValue5(billVo.getValue5());
		bill.setValue6(billVo.getValue6());
		bill.setValue7(billVo.getValue7());
		bill.setValue8(billVo.getValue8());
		bill.setValue9(billVo.getValue9());
		bill.setValue10(billVo.getValue10());
		
		bill.setDouble1(billVo.getDouble1());
		bill.setDouble2(billVo.getDouble2());
		bill.setDouble3(billVo.getDouble3());
		bill.setDouble4(billVo.getDouble4());
		bill.setDouble5(billVo.getDouble5());
		bill.setDouble6(billVo.getDouble6());
		bill.setDouble7(billVo.getDouble7());
		bill.setDouble8(billVo.getDouble8());
		bill.setDouble9(billVo.getDouble9());
		bill.setDouble10(billVo.getDouble10());
		
		bill.setOperator(billVo.getOperator());
		bill.setLastModifier(operator);
		bill.setLastModifiedTime(DateUtils.formatDateHms(now));
		bill.addTransaction(transaction);
		transaction.setBill(bill);
		
		List<BillDetailVo> billDetailVoList = billVo.getBillDetailVo();
		for (BillDetailVo billDetailVo : billDetailVoList) {
			String sysFlag=billDetailVo.getSysFlag();
			if (Constants.SYS_FLAG_DELETED.equals(sysFlag)){
				continue;
			}
			String transactionDetailTypeId = billDetailVo.getTransactionDetailTypeId();
			TransactionDetail transactionDetail=StorageFactory.getInstance().createTransactionDetail(transactionDetailTypeId);
			if(StringUtils.isNotBlank(billDetailVo.getUnitId())){
				Dictionary unit = dictionaryRepository.get(billDetailVo.getUnitId());
				transactionDetail.setUnit(unit);
			}
			if(StringUtils.isNotBlank(billDetailVo.getMaterielId())){
				Dictionary materiel = dictionaryRepository.get(billDetailVo.getMaterielId());
				transactionDetail.setMateriel(materiel);
			}
			if(StringUtils.isNotBlank(billDetailVo.getOriginEntityId())){
				Dictionary originEntity = dictionaryRepository.get(billDetailVo.getOriginEntityId());
				transactionDetail.setOriginEntity(originEntity);
			}
			if(StringUtils.isNotBlank(billDetailVo.getTargetEntityId())){
				Dictionary targetEntity = dictionaryRepository.get(billDetailVo.getTargetEntityId());
				transactionDetail.setTargetEntity(targetEntity);
			}
			
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic1Id())){
				Dictionary otherdic1 = dictionaryRepository.get(billDetailVo.getOtherDic1Id());
				transactionDetail.setOtherDic1(otherdic1);
			} 
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic2Id())){
				Dictionary otherdic2 = dictionaryRepository.get(billDetailVo.getOtherDic2Id());
				transactionDetail.setOtherDic1(otherdic2);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic3Id())){
				Dictionary otherdic3 = dictionaryRepository.get(billDetailVo.getOtherDic3Id());
				transactionDetail.setOtherDic3(otherdic3);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic4Id())){
				Dictionary otherdic4 = dictionaryRepository.get(billDetailVo.getOtherDic4Id());
				transactionDetail.setOtherDic4(otherdic4);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic5Id())){
				Dictionary otherdic5 = dictionaryRepository.get(billDetailVo.getOtherDic5Id());
				transactionDetail.setOtherDic1(otherdic5);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic6Id())){
				Dictionary otherdic6 = dictionaryRepository.get(billDetailVo.getOtherDic6Id());
				transactionDetail.setOtherDic1(otherdic6);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic7Id())){
				Dictionary otherdic7 = dictionaryRepository.get(billDetailVo.getOtherDic7Id());
				transactionDetail.setOtherDic1(otherdic7);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic8Id())){
				Dictionary otherdic8 = dictionaryRepository.get(billDetailVo.getOtherDic8Id());
				transactionDetail.setOtherDic1(otherdic8);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic9Id())){
				Dictionary otherdic9 = dictionaryRepository.get(billDetailVo.getOtherDic9Id());
				transactionDetail.setOtherDic1(otherdic9);
			}  
			if(StringUtils.isNotBlank(billDetailVo.getOtherDic10Id())){
				Dictionary otherdic10 = dictionaryRepository.get(billDetailVo.getOtherDic10Id());
				transactionDetail.setOtherDic1(otherdic10);
			}  
			
			transactionDetail.setValue1(billDetailVo.getValue1());
			transactionDetail.setValue2(billDetailVo.getValue2());
			transactionDetail.setValue3(billDetailVo.getValue3());
			transactionDetail.setValue4(billDetailVo.getValue4());
			transactionDetail.setValue5(billDetailVo.getValue5());
			transactionDetail.setValue6(billDetailVo.getValue6());
			transactionDetail.setValue7(billDetailVo.getValue7());
			transactionDetail.setValue8(billDetailVo.getValue8());
			transactionDetail.setValue9(billDetailVo.getValue9());
			transactionDetail.setValue10(billDetailVo.getValue10());
			
			transactionDetail.setDouble1(billDetailVo.getDouble1());
			transactionDetail.setDouble2(billDetailVo.getDouble2());
			transactionDetail.setDouble3(billDetailVo.getDouble3());
			transactionDetail.setDouble4(billDetailVo.getDouble4());
			transactionDetail.setDouble5(billDetailVo.getDouble5());
			transactionDetail.setDouble6(billDetailVo.getDouble6());
			transactionDetail.setDouble7(billDetailVo.getDouble7());
			transactionDetail.setDouble8(billDetailVo.getDouble8());
			transactionDetail.setDouble9(billDetailVo.getDouble9());
			transactionDetail.setDouble10(billDetailVo.getDouble10());
			
			transactionDetail.setPrice(billDetailVo.getPrice());
			transactionDetail.setMoney(billDetailVo.getMoney());
			transactionDetail.setTransaction(transaction);
			transaction.addTransactionDetail(transactionDetail);
			
			transactionDetail.setAmount(billDetailVo.getAmount());
			transactionDetail.setSysFlag(Constants.SYS_FLAG_USEING);
			transactionDetail.setCreateTime(DateUtils.formatDateHms(now));
			transactionDetail.setCreator(operator);
			transactionDetail.setLastModifiedTime(DateUtils.formatDateHms(now));
			transactionDetail.setLastModifier(operator);
			String stateId=billDetailVo.getStateId();
			if (StringUtils.isNotBlank(stateId)){
				transactionDetail.setState(dictionaryRepository.get(billDetailVo.getStateId()));
			}
			
			/*
			if(StringUtils.isNotBlank(billDetailVo.getStateId())){
				Dictionary state = dictionaryRepository.get(billDetailVo.getStateId());
			}
			*/
			//transactionDetailRepository.save(transactionDetail);
			//transactionDetail.createOrUpdateStorage(storageRepository, state,operator);
			//transactionDetail.createAccount(accountRepository, operator);
		}
		billRepository.save(bill);
		transaction.commit(storageRepository, accountRepository, operator);
		
		return bill;
	}



	
	
}
